#region Namespaces

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;

#endregion

namespace Vibstudio.X4NET.Xml.Linq
{
    internal static class XUtil
    {
        public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";

        public static bool ConvertToBoolean(string s)
        {
            return XmlConvert.ToBoolean(s.ToLower(CultureInfo.InvariantCulture));
        }

        public static DateTime ToDateTime(string s)
        {
            try
            {
                return XmlConvert.ToDateTime(s, XmlDateTimeSerializationMode.RoundtripKind);
            }
            catch
            {
                return DateTime.Parse(s);
            }
        }

        public static string ToString(object o)
        {
            if (o == null)
            {
                throw new InvalidOperationException("Attempt to get string from null");
            }

            switch (Type.GetTypeCode(o.GetType()))
            {
                case TypeCode.String:
                    return (string)o;
                case TypeCode.DateTime:
                    return XmlConvert.ToString((DateTime)o, XmlDateTimeSerializationMode.RoundtripKind);
                case TypeCode.Decimal:
                    return ((decimal)o).ToString(CultureInfo.InvariantCulture);
                case TypeCode.Double:
                    return ((double)o).ToString("r", CultureInfo.InvariantCulture);
                case TypeCode.Single:
                    return ((float)o).ToString("r", CultureInfo.InvariantCulture);
                case TypeCode.Boolean:
                    return o.ToString().ToLower();
                default:
                    if (o is TimeSpan)
                    {
                        return XmlConvert.ToString((TimeSpan)o);
                    }
                    if (o is DateTimeOffset)
                    {
                        return XmlConvert.ToString((DateTimeOffset)o);
                    }
                    return o.ToString();
            }
        }

        public static bool ToBoolean(object o)
        {
            throw new NotImplementedException();
        }

        public static bool? ToNullableBoolean(object o)
        {
            throw new NotImplementedException();
        }

        public static IEnumerable<object> ExpandArray(object o)
        {
            XNode n = o as XNode;
            if (n != null)
            {
                yield return n;
            }
            else if (o is string)
            {
                yield return o;
            }
            else if (o is IEnumerable)
            {
                foreach (object obj in (IEnumerable)o)
                {
                    foreach (object oo in ExpandArray(obj))
                    {
                        yield return oo;
                    }
                }
            }
            else
            {
                yield return o;
            }
        }

        public static XNode ToNode(object o)
        {
            if (o is XAttribute)
            {
                throw new ArgumentException("Attribute node is not allowed as argument");
            }
            XNode n = o as XNode;
            if (n != null)
            {
                return n;
            }
            if (o is string)
            {
                return new XText((string)o);
            }
            return new XText(ToString(o));
        }

        public static object GetDetachedObject(XObject child)
        {
            return child.Owner != null ? Clone(child) : child;
        }

        public static object Clone(object o)
        {
            if (o is string)
            {
                return o;
            }
            if (o is XAttribute)
            {
                return new XAttribute((XAttribute)o);
            }
            if (o is XElement)
            {
                return new XElement((XElement)o);
            }
            if (o is XCData)
            {
                return new XCData((XCData)o);
            }
            if (o is XComment)
            {
                return new XComment((XComment)o);
            }
            if (o is XProcessingInstruction)
            {
                return new XProcessingInstruction((XProcessingInstruction)o);
            }
            if (o is XDeclaration)
            {
                return new XDeclaration((XDeclaration)o);
            }
            if (o is XDocumentType)
            {
                return new XDocumentType((XDocumentType)o);
            }
            if (o is XText)
            {
                return new XText((XText)o);
            }
            throw new ArgumentException();
        }
    }
}